﻿using CgdataBase;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using MessageBox = FolderCompare.Views.MessageBox;

namespace FolderCompare
{
    public partial class App : Application
    {
        private static AppSettings Settings => AppSettings.Instance;
        private static DataHelper DbHelper => DataHelper.Instance;

        #region 防止多开

        private Mutex mMutex;
        private bool mCreatedNew;
        private bool mInitiallyOwned = true;

        #endregion 防止多开

        public App()
        {
            GetUnhandledException();
            JsonHelper.Instance = new JsonController();
            UISettings.Instance.Init(false);
            AppSettings.Instance.Init(false);

            string assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;

            FileSystemHelper.TryCreateDirectory(GetAppDataPath());

            #region 防止多开

            mMutex = new Mutex(mInitiallyOwned, assemblyName, out mCreatedNew);
            if (!mCreatedNew)
            {
                PipeController.Instance.WakeUpServer();

                Environment.Exit(0);
                return;
            }

            PipeController.Instance.Start();

            #endregion 防止多开

            InitializeDatabase();

            this.Exit += (s, e) =>
            {
                PipeController.Instance.Stop();
                DataHelper.DB?.Dispose();
            };
        }

        public static void InitializeDatabase()
        {
            if (!Settings.OfflineMode)
            {
                DbHelper.Initialize(Settings.DatabaseType, Settings.DatabaseConnectionString, Settings.UseAutoSyncStructure);
            }
            else
            {
                var filePath = Path.Combine(GetAppDataPath(), "database.db");
                DbHelper.Initialize(FreeSql.DataType.Sqlite, DataHelper.GetSqliteConnectionString(filePath), Settings.UseAutoSyncStructure);
            }
        }

        private static string GetAppDataPath()
        {
            return ConfigController.GetAppDataPath(Assembly.GetExecutingAssembly().GetName().Name);
        }

        public static Window GetActiveWindow()
        {
            return Application.Current.Windows.Cast<Window>().FirstOrDefault(s => s.IsActive == true);
        }

        public static T GetWindow<T>(Func<T, bool> predicate = null) where T : Window
        {
            if (Application.Current.MainWindow is T)
            {
                return (T)Application.Current.MainWindow;
            }

            var windows = predicate == null
                ? Application.Current.Windows.OfType<T>().ToList()
                : Application.Current.Windows.OfType<T>().Where(predicate).ToList();

            T result = null;
            if (windows.Count == 1)
            {
                result = windows.Single();
            }
            else if (windows.Count > 1)
            {
                result = windows.Last();
                windows.Remove(result);
                windows.ForEach(item => item.Close());
            }

            return result;
        }

        private void GetUnhandledException()
        {
            this.DispatcherUnhandledException += (s, e) =>
            {
                LogHelper.Error(e.Exception);
                MessageBox.Show(e.Exception.Message);
                e.Handled = true;
            };
            //Task线程内未捕获异常处理事件
            TaskScheduler.UnobservedTaskException += (s, e) =>
            {
                LogHelper.Error(e.Exception);
                MessageBox.Show(e.Exception.Message);
                e.SetObserved();//设置该异常已察觉（这样处理后就不会引起程序崩溃）
            };
            //非UI线程未捕获异常处理事件
            AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            {
                if (e.ExceptionObject is Exception ex)
                {
                    LogHelper.Error(ex);
                }
                else
                {
                    LogHelper.Error(e.ExceptionObject.ToString());
                }
            };
        }
    }
}